package ro.peoplecentric.ctc.faces;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import javax.faces.component.UIComponent;
import javax.faces.component.UISelectItems;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.model.SelectItem;

/**
 * Collection of utility methods for working with {@link SelectItem} or data
 * represented by them.
 * 
 * @author pguzun
 */
public final class SelectItemsUtils {

	private static final String ERROR_UNKNOWN_SELECT_TYPE = "A value expression of type '%s' is disallowed for a select item";

	private SelectItemsUtils() {
	}

	public static Object findValueByStringConversion(FacesContext context, UIComponent component, String value, Converter converter) {
		return findValueByStringConversion(context, component, collectItemValuesFromParent(component), value, converter);
	}

	private static Object findValueByStringConversion(FacesContext context, UIComponent component, List<Object> itemValues, String value, Converter converter) {
		if (value != null) {
			for (Object itemValue : itemValues) {
				String convertedItemValue = converter.getAsString(context, component, itemValue);
				if (value.equals(convertedItemValue)) {
					return itemValue;
				}
			}
		}
		return null;
	}

	@SuppressWarnings("unchecked")
	private static List<Object> collectItemValuesFromParent(UIComponent component) {
		final List<Object> itemValues = new ArrayList<>();
		// Iterate over all children of the parent component. Non-UISelectItems
		// children are automatically skipped.
		for (UIComponent child : component.getChildren()) {
			if (child instanceof UISelectItems) {

				UISelectItems uiSelectItems = (UISelectItems) child;
				Object value = uiSelectItems.getValue();

				if (value instanceof Object[]) {
					itemValues.addAll(Arrays.asList((Object[]) value));
				} else if (value instanceof Collection) {
					itemValues.addAll((Collection<? extends Object>) value);
				} else if (value instanceof Map) {
					itemValues.addAll(((Map<?, ?>) value).values());
				} else {
					// A value binding was specified, but of a type we don't
					// support.
					throw new IllegalArgumentException(String.format(ERROR_UNKNOWN_SELECT_TYPE, value.getClass().toString()));
				}
			}
		}
		return itemValues;
	}
}
